package pt.isel.pdm.ouryamba;

import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

/**
 * Represents the class that will execute the CRUD methods that allow database interaction.
 * */
public class DbStatusProvider extends ContentProvider
{
	/**
	 * Is the authority component of the URI of the database.
	 * */
	public static final  String AUTHORITY = "pt.isel.pdm.ouryamba.contentprovider";
	/**
	 * Is the complete URI of the database.
	 * */
	public static final Uri CONTENT_URI = Uri.parse(ContentResolver.SCHEME_CONTENT + "://" + AUTHORITY);
	/***
	 * Represents the object that will retrieve the objects to write and read over the database.
	 * */
	private DbHelper dbHelper;
	/**
	 * Represents the identifier for the type of URI that shall represent a collection of statuses.
	 * */
	private static final int STATUS_ALL = 0;
	/**
	 * Represents the identifier for the type of URI that shall represent a single of status.
	 * */
	private static final int STATUS_ID  = 1;
	/**
	 * Is the {@code UriMatcher} object that will compare requested URI's with the ones available.
	 * */
	private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
	/**
	 * Represents the MIME type of the representation returned from the URI of collection of statuses.
	 * */
	private static final String MIME_STATUS_ALL = "vnd.android.cursor.dir/vnd.pdm.ouryamba." + DbStatusContract.TABLE;
	/**
	 * Represents the MIME type of the representation returned from the URI of a single of status.
	 * */
	private static final String MIME_STATUS_ONE = "vnd.android.cursor.item/vnd.pdm.ouryamba." + DbStatusContract.TABLE;
	
	/**
	 * Static block of code that will run only once per load of this type into memory.
	 * 
	 * Simply adds the available URI's for the content receiver's requests.
	 * */
	static
	{
		uriMatcher.addURI(AUTHORITY, DbStatusContract.TABLE, STATUS_ALL);
		uriMatcher.addURI(AUTHORITY, DbStatusContract.TABLE + "/#", STATUS_ID);
	}
	
	
//ContentProvider methods
	
	/**
	 * Initializes the {@code dbHelper} variable with the reference that binds to database of this application.
	 * 
	 * @return true Because the provider was successfully initiated.
	 * */
	@Override
	public boolean onCreate()
	{
		dbHelper = new DbHelper(getContext());
		return true;
	}

	/**
	 * Returns the MIME type of each possible element that could be returned on a query over the database.</br>
	 * 
	 * @param uri Is the URI of the element that will be queried and which MIME type is requested.
	 * @return The MIME type related to the parameter {@code uri}.
	 * */
	@Override
	public String getType(Uri uri)
	{
		if(uriMatcher.match(uri) == STATUS_ALL)
		{
			return MIME_STATUS_ALL;
		}
		return MIME_STATUS_ONE;
	}
	
	/**
	 * Performs a delete query over the database which can be used to delete one or multiple elements.</br>
	 * 
	 * If the URI is for one specific element, the ID column is inserted in the selection string.
	 * 
	 * @param uri Is the URI which the delete request will be done.
	 * @param sel Is the selection string which should contain the columns for the where clause.
	 * @param argSel Are the values of each column of the selection string
	 * @return The number of tuples deleted.
	 * @see #makeSelection(Uri, String)
	 * */
	@Override
	public int delete(Uri uri, String sel, String[] argSel) 
	{
		sel = makeSelection(uri, sel);
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		try
		{
			return db.delete(DbStatusContract.TABLE, sel, argSel);
		}
		finally
		{
			db.close();
		}
	}

	/**
	 * Performs an insert query over the database.</br>
	 * 
	 * @param uri Is the URI which the insert request will be done.
	 * @param cv Are the values for each column of the new tuple.
	 * @return The URI of the new element.
	 * */
	@Override
	public Uri insert(Uri uri, ContentValues cv)
	{
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		try
		{
			long row = db.insert(DbStatusContract.TABLE, null, cv);
			if(row==-1)
			{
				return null;
			}
			return ContentUris.withAppendedId(uri, row);
		}
		finally
		{
			db.close();
		}
	}

	/**
	 * Performs a select query over the database which can be used to select one or multiple elements.</br>
	 * 
	 * If the URI is for one specific element, the ID column is inserted in the selection string.
	 * 
	 * @param uri Is the URI which the select request will be done.
	 * @param proj Are the columns desired to be projected/shown on the final result.
	 * @param sel Is the selection string which should contain the columns for the where clause.
	 * @param argSel Are the values of each column of the selection string
	 * @param sort Are the order options that could be included in the query to order the data.
	 * @return The cursor for the selection requested.
	 * @see #makeSelection(Uri, String)
	 * */
	@Override
	public Cursor query(Uri uri, String[] proj, String sel, String[] argSel, String sort)
	{
		sel = makeSelection(uri, sel);
		SQLiteDatabase db = dbHelper.getReadableDatabase();
		return db.query(DbStatusContract.TABLE, proj, sel, argSel, null, null, sort);
	}
	
	/**
	 * Performs an update query over the database which can be used to update one or multiple elements.</br>
	 * 
	 * If the URI is for one specific element, the ID column is inserted in the selection string.
	 * 
	 * @param uri Is the URI which the delete request will be done.
	 * @param cv Are the new values to update.
	 * @param sel Is the selection string which should contain the columns for the where clause.
	 * @param argSel Are the values of each column of the selection string
	 * @return The number of tuples updated.
	 * @see #makeSelection(Uri, String)
	 * */
	@Override
	public int update(Uri uri, ContentValues cv, String sel, String[] argSel)
	{
		sel = makeSelection(uri, sel);
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		try 
		{
			return db.update(DbStatusContract.TABLE, cv, sel, argSel);
		} 
		finally 
		{	
			db.close();
		}
	}
	
	
//Own methods
	
	/**
	 * Analysis the URI and see whether the URI is for one specific element or not, to determine the 
	 * appropriate selection string for that request. </br>
	 * 
	 * If the URI is for a specific element, then the selection string will only have the ID column.
	 * Otherwise, the selection string is discarded (could return null or not).
	 *  
	 * @param uri Is the URI of the request.
	 * @param sel Is the selection string of the request.
	 * @return The appropriate selection string according to the URI of the request. Can return null.
	 * @see #uriMatcher
	 * @see #STATUS_ID
	 * @see #STATUS_ALL 
	 * */
	private String makeSelection(Uri uri, String sel) 
	{
		switch (uriMatcher.match(uri))
		{
		  case STATUS_ID:	
			  return DbStatusContract.ID + "=" + uri.getLastPathSegment();
		  default:
			  return sel;
		}
	}

}
